<template>
  <div class="o-select">
    <Select
      v-model="value"
      filterable
      clearable
      transfer
      label-in-value
      ref="select"
      :disabled="renderOpts.props.disabled"
      :placeholder="renderOpts.props.placeholder"
      :class="'align-' + align"
      @on-change="onChange"
      @on-clear="onClear"
      @on-open-change="onOpen"
      @mouseleave="onMouseleave"
      @mouseenter="onMouseenter"
    >
      <Option v-for="(item, idx) of list" :key="idx" :value="item.value">{{
        $srv.getI18nBySrv(item.label)
      }}</Option>
    </Select>
  </div>
</template>
<script lang="ts">
import { T_srv, Tsrv, vue } from '@/services';
import { Input, Select } from 'view-design';

@T_srv.comp
export default class oSelect extends vue {
  // modify by wiz
  public compName: string = 'oSelect';

  /**
   * props
   */
  @T_srv.prop() renderOpts: any;

  @T_srv.prop() params: any;

  private value = null;

  private list: any = [];

  private input: any = null;

  private startValue = null;

  private optionId = null;

  private align = 'left';

  private Tcommand: any = null;

  private currFieldName: string = '';

  private optIsLoad: boolean = false;

  private G_paramsFromComp: 'oBaseGrid' | 'oBaseForm' = null;

  /**
   * data
   */
  @T_srv.watch('params')
  onParamsChange() {
    this.initProps();
    this.setValue();
  }

  @T_srv.watch('renderOpts')
  onRenderOptsChange() {
    this.initProps();
    this.init();
  }

  created() {
    this.Tcommand = this.renderOpts.props.getTcommand();
    // if (this.renderOpts.props.getTcommand()?.oBaseGrid?.G_compName) {
    //   this.G_paramsFromComp = 'oBaseGrid';
    // } else if (this.renderOpts.props.getTcommand()?.oBaseForm?.G_compName) {
    //   this.G_paramsFromComp = 'oBaseForm';
    // } else {
    //   this.$msg({});
    //   console.error('未定义的组件');
    // }
    if (
      !Tsrv.utils.noValue(this.params) &&
      // this.params.hasOwnProperty('property')
      Object.prototype.hasOwnProperty.call(this.params, 'property')
    ) {
      this.G_paramsFromComp = 'oBaseForm';
    } else {
      this.G_paramsFromComp = 'oBaseGrid';
    }
    this.init();
  }

  mounted() {
    this.initProps();
    this.input = (this.$refs.select as Select).$children[0] as Input;
    this.input['onInputFocus'] = () => {
      this.emitEvent('focus');
    };
    this.input['onInputBlur'] = () => {
      this.emitEvent('blur');
    };
    this.addCustomEvents();
  }

  private initProps() {
    if (this.params.property) {
      const items = this.params.$form.items;
      const find = Tsrv.utils.find(
        items,
        el => el.field === this.params.property
      );
      if (find) {
        this.align = find.align || 'left';
      }
    } else {
      this.align = this.params.column.align || 'left';
    }
  }

  public init() {
    if (this.G_paramsFromComp === 'oBaseGrid') {
      this.currFieldName = this.params.column.property;
    } else {
      this.currFieldName = this.params.property;
      this.getOptList();
    }
    // this.getOptList();
  }

  private getSlcRow(row: { [key: string]: any }): { [key: string]: any } {
    const slcM2oField: { [key: string]: any } = {};
    for (const k of Object.keys(row)) {
      if (/^(slc|m2o)\\|/.test(k)) {
        const fs = k.split(`|`);
        if (fs.length > 2) {
          slcM2oField[fs[1]] = row[fs[1]];
        }
      }
    }
    return slcM2oField;
  }

  private getOptList() {
    if (this.optIsLoad) {
      return;
    }
    if (!Tsrv.utils.noValue(this.renderOpts.props.optionId)) {
      const funName = this.renderOpts.props.funName;
      const funInfo = Tsrv.getFunInfo(
        Tsrv.getMainFunInfoByFunName(funName)?.mainFun
      );
      const d =
        this.G_paramsFromComp === 'oBaseGrid'
          ? this.params.row
          : this.params.data;
      const slcM2oField = this.getSlcRow(Tsrv.utils.clone(d));
      // 有级联查询规则
      if (!Tsrv.utils.noValue(this.renderOpts.props?.cascadeFilter)) {
        const p = {
          inputArgs: [
            { name: 'funName', dataType: 'string', value: funName ?? '' },
            {
              name: 'fieldName',
              dataType: 'string',
              value:
                // this.params.$table.getTableColumn().fullColumn[
                //   this.params.columnIndex
                // ].title ?? ''
                this.params.column.property ?? ''
            },
            {
              name: 'currRow',
              dataType: 'string',
              value: slcM2oField
            }
          ]
        };
        Tsrv.doEvent(
          this.renderOpts.props.cascadeFilter,
          funInfo,
          () => p,
          false
        )
          .then(resp => {
            if (resp.isErr()) {
              console.error(resp.errmsg);
            }
            const data = resp.getReturnData(`conf`);
            if (!Tsrv.utils.noValue(data?.res.success) && !data.res.success) {
              console.error(data.res.msg);
            }
            const outArg = data?.res?.data.outArg;
            if (!Tsrv.utils.noValue(outArg) && Array.isArray(outArg)) {
              const result = outArg[0];
              if (result.name === 'result' && result.dataType === 'string') {
                if (Tsrv.utils.noValue(result?.value)) {
                  this.getList();
                } else {
                  this.getList(JSON.parse(result.value.replace(/'/g, '"')));
                }
              }
            } else {
              this.getList();
            }
          })
          .catch(er => {
            console.error(er);
          });
      } else {
        this.getList();
      }
    }
  }

  private getList(filter: any = null) {
    if (Tsrv.utils.noValue(filter)) {
      filter = null;
    }
    const id = this.renderOpts.props.optionId;
    const lang = this.$i18n.locale || 'en-US';
    const dbType = this.renderOpts.props.dbType;
    this.optionId = id;
    Tsrv.getSLCData(id, dbType, lang, filter).then(r => {
      const [b, res, msg] = r;
      !b && msg && this.$msg(msg);
      this.list = res;
      this.renderOpts.props.optionLoaded = res;
      this.setValue();
    });
  }

  private focus() {
    (this.input.$refs.input as HTMLInputElement).focus();
    (this.input.$refs.input as HTMLInputElement).click();
  }

  public resetValue() {
    this.setValue(null);
  }

  public setValue(val: any = undefined) {
    const d =
      this.G_paramsFromComp === 'oBaseGrid'
        ? this.params.row
        : this.params.data;
    const rowVal = d[this.currFieldName];
    this.value = val;
    // 初始化
    if (val === undefined) {
      this.value = Number.isNaN(Number(rowVal)) ? rowVal : Number(rowVal);
    }
    this.setTableValue(this.value);
  }

  setTableValue(val: number | string) {
    if (val !== undefined) {
      const find = Tsrv.utils.find(this.list, el => el.value === val);
      const label = find ? find?.label : '';
      const d =
        this.G_paramsFromComp === 'oBaseGrid'
          ? this.params.row
          : this.params.data;
      d[this.currFieldName] = val;
      // params中没有 slc| 开头的属性，需要手动添加
      // const regEx = new RegExp(`^slc\\|${this.currFieldName}`);
      // for (const k of Object.keys(d)) {
      //   if (regEx.test(k)) {
      //     d[k] = label;
      //   }
      // }
      if (this.G_paramsFromComp === 'oBaseGrid') {
        this.params.row[this.params.column.property] = val;
        this.params.row[
          `slc|${this.params.column.property}|${this.renderOpts.props.optionId}`
        ] = label;
      } else {
        this.params.data[this.params.property] = val;
        this.params.data[
          `slc|${this.params.property}|${this.renderOpts.props.optionId}`
        ] = label;
      }
    }
  }

  onOpen(e) {
    this.getOptList();
    if (e) {
      this.startValue = this.getValue();
    }
  }

  onFocus(e) {
    this.getOptList();
  }

  onChange(e) {
    if (e) {
      this.setValue(e.value);
      this.emitEvent('change');
      if (this.startValue !== this.getValue()) {
        this.emitEvent('dochange');
      }
    }
  }

  onMouseleave(e) {
    this.emitEvent('mouseleave');
  }

  onMouseenter(e) {
    this.emitEvent('mouseenter');
  }

  getValue() {
    return this.params.property
      ? this.params.data[this.params.property]
      : this.params.row[this.params.column.property];
  }

  emitEvent(event: string) {
    const ev = this.renderOpts.events;
    // 深拷贝有问题
    const params = Tsrv.utils.cloneNoMatchVue(this.params, true);

    params.from = 'select';
    let fns = null;
    for (const action in ev) {
      if (ev[action] && action === `on-${event}`) {
        fns = ev[action];
        break;
      }
    }
    if (fns !== null) fns(params, event);
  }

  onClear() {
    this.setValue(null);
    this.emitEvent('change');
    if (this.startValue !== this.getValue()) {
      this.emitEvent('dochange');
    }
  }

  private addCustomEvents() {
    ((this.$refs.select as Select).$el as HTMLInputElement).addEventListener(
      'mouseenter',
      this.onMouseenter
    );
    ((this.$refs.select as Select).$el as HTMLInputElement).addEventListener(
      'mouseleave',
      this.onMouseleave
    );
  }

  private destroyCustomEvents() {
    ((this.$refs.select as Select).$el as HTMLInputElement).removeEventListener(
      'mouseenter',
      this.onMouseenter
    );
    ((this.$refs.select as Select).$el as HTMLInputElement).removeEventListener(
      'mouseleave',
      this.onMouseleave
    );
  }

  beforeDestroy() {
    this.destroyCustomEvents();
  }
}
</script>
